﻿using IOA.MES.Client.Common;
using IOA.MES.Client.Models.Response;
using IOA.MES.Client.Settings;
using IOA.MES.Common;
using NLog;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.OleDb;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using System.Diagnostics;
using System.Reflection;

namespace IOA.MES.Client.IV
{
    /// <summary>
    /// IVIndex.xaml 的交互逻辑
    /// </summary>
    public partial class IVIndex : Window
    {
        private List<ViaSiteRecord> records { get; set; } = new List<ViaSiteRecord>();
        private List<Machine> machines { get; set; } = new List<Machine>();
        private FileSystemWatcher imageFolderWatcher;
        private FileSystemWatcher dataFileWatcher;
        private string lastBarCode = string.Empty;
        private string lastImage = string.Empty;
        private List<KeyValuePair<string, string>> ivDatas = new List<KeyValuePair<string, string>>();
        private WinIVResult winIvResult;
        private string curDirectory;

        public IVIndex()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            var dataMonitorFile = BaseEnv.GetStorage("IVDataMonitorFolder");
            if (Directory.Exists(dataMonitorFile))
            {
                txtDataFolder.Text = dataMonitorFile;
                WatchDataChanges(dataMonitorFile);
            }

            var imageMonitorFolder = BaseEnv.GetStorage("IVImageMonitorFolder");
            if (Directory.Exists(imageMonitorFolder))
            {
                txtImageFolder.Text = imageMonitorFolder;
                WatchImageChanges(imageMonitorFolder);
            }

            txtTrueName.Content = BaseEnv.UserInfo.TrueName;
            InitDuties();
            InitMachines();

            winIvResult = new WinIVResult();
            winIvResult.Show();
        }

        #region 初始化数据
        public void InitDuties()
        {
            var duties = BaseEnv.InvokeApi<QueryDutiesResponse>("/api/Auth/QueryDuties", new { WorkshopCode = BaseEnv.WorkshopCode }).Data.Duties;

            cbDuties.ItemsSource = duties;
            cbDuties.DisplayMemberPath = "DutyName";
            cbDuties.SelectedValuePath = "DutyId";

            if (duties.Any())
            {
                cbDuties.SelectedIndex = 0;
            }
        }

        public void InitMachines()
        {
            machines = BaseEnv.InvokeApi<QueryMachinesResponse>("/api/Machine/QueryMachines", new { WorkshopCode = BaseEnv.WorkshopCode, MachineType = (int)MachineType.IV }).Data.Machines;
            cbMachines.ItemsSource = machines;
            cbMachines.DisplayMemberPath = "MachineName";
            cbMachines.SelectedValuePath = "MachineId";

            if (machines.Any(_ => _.MachineId == BaseEnv.MachineId))
            {
                cbMachines.SelectedIndex = machines.FindIndex(_ => _.MachineId == BaseEnv.MachineId);
            }
            else
            {
                CommonMessage.Alert(this, "请先在系统设置中重新选择设备\r\nPlease reselect the device in the system settings now"); ;
                new SettingsIndex().ShowDialog();
            }
        }

        private void InitRecords()
        {
            new TaskFactory().StartNew(() =>
            {
                Thread.Sleep(100);
                Dispatcher.Invoke(new Action(() =>
                {
                    var response = BaseEnv.InvokeApi<QueryViaSiteRecordsResponse>("/api/Machine/QueryViaSiteRecords", new { DutyId = Convert.ToInt32(cbDuties.SelectedValue), SiteType = SiteType.IVTest, MachineId = Convert.ToInt32(cbMachines.SelectedValue) });
                    if (response.ErrCode != 200)
                    {
                        CommonMessage.Alert(this, response.ErrMsg, false);
                        return;
                    }
                    this.records.Clear();
                    this.records.AddRange(response.Data.Records);
                    this.records.ForEach(_ => _.No = this.records.Count - this.records.IndexOf(_));
                    BindGridRecords();
                }));
            });
        }

        private void BindGridRecords()
        {
            gridRecords.ItemsSource = null;
            gridRecords.ItemsSource = records;
            lbTotal.Content = records.Select(_ => _.Code.ToUpper().Trim()).Distinct().Count();
        }
        #endregion

        /// <summary>
        /// 班次、机台选择
        /// </summary>
        private void cb_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var cb = sender as System.Windows.Controls.ComboBox;
            if (string.Equals(cb.Name, "cbMachines", StringComparison.CurrentCultureIgnoreCase))
            {
                var machine = machines[cb.SelectedIndex];
                if (string.IsNullOrWhiteSpace(machine.IvSql))
                {
                    CommonMessage.Alert(this, "该设备没有配置SQL语句，请联系IT\r\nThe device is not configured with SQL statements, please contact IT", false);
                    return;
                }
            }
            InitRecords();
        }

        private void btnSelectDataFile_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new FolderBrowserDialog();
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK && Directory.Exists(dialog.SelectedPath))
            {
                txtDataFolder.Text = dialog.SelectedPath;
                BaseEnv.SetStorage("IVDataMonitorFolder", dialog.SelectedPath);
                WatchDataChanges(dialog.SelectedPath);
            }
        }

        private void btnSelectImageFolder_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new FolderBrowserDialog();
            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK && Directory.Exists(dialog.SelectedPath))
            {
                txtImageFolder.Text = dialog.SelectedPath;
                BaseEnv.SetStorage("IVImageMonitorFolder", dialog.SelectedPath);
                WatchImageChanges(dialog.SelectedPath);
            }
        }

        /// <summary>
        /// 开始监听IV数据文件
        /// </summary>
        private void WatchDataChanges(string folder)
        {
            dataFileWatcher = new FileSystemWatcher(folder);
            dataFileWatcher.Changed += IVData_Changed;
            dataFileWatcher.EnableRaisingEvents = true;
            dataFileWatcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess
                                   | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size;
        }

        /// <summary>
        /// 开始监听IV图片文件
        /// </summary>
        private void WatchImageChanges(string folder)
        {
            imageFolderWatcher = new FileSystemWatcher(folder);
            imageFolderWatcher.Changed += IVImage_Changed;
            imageFolderWatcher.EnableRaisingEvents = true;
            imageFolderWatcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime | NotifyFilters.DirectoryName | NotifyFilters.FileName | NotifyFilters.LastAccess
                                   | NotifyFilters.LastWrite | NotifyFilters.Security | NotifyFilters.Size;
        }

        /// <summary>
        /// IV图片变化
        /// </summary>
        private void IVImage_Changed(object sender, FileSystemEventArgs e)
        {
            CommonMessage.Log(LogLevel.Info, $"发现文件（IVImage_Changed）：{e.ChangeType}：{e.Name}：{e.FullPath}");
            if (!new List<string> { ".jpg", ".png", ".jpeg", ".bmp" }.Contains(Path.GetExtension(e.FullPath).ToLower()))
            {
                return;
            }
            lastImage = e.FullPath;
            Thread.Sleep(2000);

            TryViaSite();
        }

        /// <summary>
        /// IV数据变化
        /// </summary>
        private void IVData_Changed(object sender, FileSystemEventArgs e)
        {
            Machine machine = null;
            Dispatcher.Invoke(new Action(() =>
            {
                machine = machines[cbMachines.SelectedIndex];
            }));
            if (string.IsNullOrWhiteSpace(machine.IvSql))
            {
                CommonMessage.Alert(this, "该设备没有配置SQL语句，请联系IT\r\nThe device is not configured with SQL statements, please contact IT", false);
                return;
            }
            if (machine.FileType == 1)
            {
                if (!string.Equals(Path.GetExtension(e.FullPath), ".csv", StringComparison.CurrentCultureIgnoreCase))
                {
                    return;
                }
            }
            else if (machine.FileType == 0)
            {
                if (!string.Equals(Path.GetExtension(e.FullPath), ".mdb", StringComparison.CurrentCultureIgnoreCase))
                {
                    return;
                }
            }
            else
            {
                CommonMessage.Alert(this, $"请配置设备厂家！");
                return;
            }
            CommonMessage.Log(LogLevel.Info, $"发现数据（IVData_Changed）：{e.ChangeType}：{e.Name}：{e.FullPath}");


            var dt = machine.FileType == 0 ? GetMdbLastData(e.FullPath, machine.IvSql) : GetCsvLastData(e.FullPath, machine.IvSql);
            OperateData(dt);
        }

        private DataTable GetMdbLastData(string fileName, string sql)
        {
            try
            {
                Thread.Sleep(2000);
                var conn = new OleDbConnection($"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={fileName}");
                conn.Open();
                var cmd = conn.CreateCommand();
                cmd.CommandText = sql;
                var dr = cmd.ExecuteReader();
                DataTable dt = new DataTable();
                if (dr.HasRows)
                {
                    for (int i = 0; i < dr.FieldCount; i++)
                    {
                        dt.Columns.Add(dr.GetName(i));
                    }
                    dt.Rows.Clear();
                }
                while (dr.Read())
                {
                    DataRow row = dt.NewRow();
                    for (int i = 0; i < dr.FieldCount; i++)
                    {
                        row[i] = dr[i];
                    }
                    dt.Rows.Add(row);
                }
                cmd.Dispose();
                conn.Close();

                return dt;
            }
            catch (Exception ex)
            {
                CommonMessage.Alert(this, $"读取Access出错\r\nError reading Access：\r\n{ex.ToString()}", false);
                return null;
            }
        }

        private DataTable GetCsvLastData(string fullPath, string ivSql)
        {
            try
            {
                var conn = new OleDbConnection($"Provider=Microsoft.Jet.OLEDB.4.0;Data Source={Path.GetDirectoryName(fullPath).TrimEnd('\\')};Extended Properties='Text;FMT=Delimited;HDR=YES;'");
                conn.Open();
                var cmd = conn.CreateCommand();
                cmd.CommandText = string.Format(ivSql, Path.GetFileName(fullPath));
                var dr = cmd.ExecuteReader();
                var dt = new DataTable();
                if (dr.HasRows)
                {
                    for (int i = 0; i < dr.FieldCount; i++)
                    {
                        dt.Columns.Add(dr.GetName(i));
                    }
                    dt.Rows.Clear();
                }
                while (dr.Read())
                {
                    DataRow row = dt.NewRow();
                    for (int i = 0; i < dr.FieldCount; i++)
                    {
                        row[i] = dr[i];
                    }
                    dt.Rows.Add(row);
                }
                cmd.Dispose();
                conn.Close();

                return dt;
            }
            catch (Exception ex)
            {
                CommonMessage.Alert(this, $"读取csv出错\r\nError reading csv：\r\n{ex.ToString()}", false);
                return null;
            }
        }

        /// <summary>
        /// 处理过站数据
        /// </summary>
        private void OperateData(DataTable dt)
        {
            ivDatas.Clear();
            if (dt == null || dt.Rows.Count <= 0)
            {
                CommonMessage.Alert(this, $"读取数据文件出错\r\nError reading data file", false);
                return;
            }
            else if (string.IsNullOrWhiteSpace(dt.Rows[0]["BarCode"].ToString()))
            {
                CommonMessage.Alert(this, "组件条码为空\r\nComponent barcode is empty", false);
                return;
            }

            lastBarCode = dt.Rows[0]["BarCode"].ToString().Trim();
            foreach (DataColumn column in dt.Columns)
            {
                ivDatas.Add(new KeyValuePair<string, string>(column.ColumnName, dt.Rows[0][column].ToString()));
            }
            var pmaxData = ivDatas.FirstOrDefault(_ => string.Equals(_.Key, "pmax", StringComparison.CurrentCultureIgnoreCase)).Value;
            if (pmaxData != null && string.IsNullOrWhiteSpace(pmaxData))
            {
                CommonMessage.Alert(this, "IV数据异常\r\nIV data abnormal", false);
                return;
            }

            TryViaSite();
        }

        private void TryViaSite()
        {
            try
            {
                dynamic viaSiteRequest = null;
                var cbImageChecked = (bool?)false;
                Dispatcher.Invoke(new Action(() =>
                {
                    viaSiteRequest = new
                    {
                        SiteType = SiteType.IVTest,
                        DutyId = Convert.ToInt32(cbDuties.SelectedValue),
                        MachineId = Convert.ToInt32(cbMachines.SelectedValue),
                        Code = ivDatas.FirstOrDefault(_ => string.Equals(_.Key, "BarCode", StringComparison.CurrentCultureIgnoreCase)).Value,
                        IVData = ivDatas,
                        Images = new List<string>()
                    };
                    cbImageChecked = cbImage.IsChecked;
                }));

                var imageBarCode = string.IsNullOrWhiteSpace(lastImage) ? string.Empty : Path.GetFileNameWithoutExtension(lastImage).Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries)[0];
                if (cbImageChecked == true && !string.Equals(imageBarCode, lastBarCode, StringComparison.CurrentCultureIgnoreCase))
                {
                    CommonMessage.Log(LogLevel.Warn, $"条码不匹配，图片BarCode：{imageBarCode}，数据BarCode：{lastBarCode}");
                    return;
                }
                CommonMessage.Log(LogLevel.Info, $"条码匹配，图片BarCode：{imageBarCode}，数据BarCode：{lastBarCode}");

                if (cbImageChecked == true)
                {
                    try
                    {
                        var getComponentResponse = BaseEnv.InvokeApi<GetComponentResponse>("/api/Machine/GetComponent", new { BarCode = viaSiteRequest.Code });
                        bool getComponentResult = false;
                        Dispatcher.Invoke(new Action(() =>
                        {
                            if (getComponentResponse.ErrCode != 200)
                            {
                                mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Fail.wav");
                                mediaElResult.Play();
                                CommonMessage.Alert(this, getComponentResponse.ErrMsg, false);
                                return;
                            }
                            else if (getComponentResponse.Data == null || getComponentResponse.Data.Component == null)
                            {
                                mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Fail.wav");
                                mediaElResult.Play();
                                CommonMessage.Alert(this, $"组件不存在\r\nComponent does not exist：\r\n{viaSiteRequest.Code}", false);
                                return;
                            }

                            if (winIvResult != null && PresentationSource.FromVisual(winIvResult) != null)
                            {
                                winIvResult.SetComponent(getComponentResponse.Data.Component);
                            }
                            getComponentResult = true;
                        }));
                        if (!getComponentResult)
                        {
                            return;
                        }
                        var tmpDirectory = $"/{BaseEnv.WorkshopCode}/IV/{getComponentResponse.Data.Component.WorkOrderNo}";
                        if (string.IsNullOrWhiteSpace(curDirectory) || !string.Equals(curDirectory, tmpDirectory, StringComparison.CurrentCultureIgnoreCase))
                        {
                            new FtpUtils(BaseEnv.UserInfo.FtpConfig.FtpRoot, BaseEnv.UserInfo.FtpConfig.UserName, BaseEnv.UserInfo.FtpConfig.Password).CheckAndCreateDirectory(tmpDirectory);
                            curDirectory = tmpDirectory;
                        }
                        var fileName = $"{curDirectory}/{viaSiteRequest.Code}_{DateTime.Now:yyMMddHHmmss}.jpg";
                        var fileBytes = File.ReadAllBytes(lastImage);
                        new FtpUtils(BaseEnv.UserInfo.FtpConfig.FtpRoot, BaseEnv.UserInfo.FtpConfig.UserName, BaseEnv.UserInfo.FtpConfig.Password).Upload(fileBytes, fileName);
                        viaSiteRequest.Images.Add($"{BaseEnv.UserInfo.FtpConfig.FtpRoot}/{fileName}");
                    }
                    catch (Exception ex)
                    {
                        CommonMessage.Alert(this, $"图片上传失败：{ex.Message}", false);
                        return;
                    }
                }

                var response = BaseEnv.InvokeApi<ViaSiteResponse>("/api/Machine/ViaSite", viaSiteRequest);
                Dispatcher.Invoke(new Action(() =>
                {
                    if (response.ErrCode != 200)
                    {
                        mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Fail.wav");
                        mediaElResult.Play();
                        CommonMessage.Alert(this, response.ErrMsg, false);
                        return;
                    }
                    else if (response.Data.StandardTestResult != null)
                    {
                        if (response.Data.StandardTestResult.Pass)
                        {
                            CommonMessage.Log(LogLevel.Info, $"标片测试通过：{lastBarCode}");
                            CommonMessage.Alert(this, $"标片测试合格！\r\nPass the standard test！", false);
                        }
                        else
                        {
                            CommonMessage.Log(LogLevel.Info, $"标片测试不通过：{lastBarCode}，异常信息：{response.Data.StandardTestResult.ErrMsg}");
                            CommonMessage.Alert(this, response.Data.StandardTestResult.ErrMsg, false);
                        }
                        return;
                    }
                    CommonMessage.Log(LogLevel.Info, $"过站成功：{lastBarCode}");
                    mediaElResult.Source = new Uri($"{BaseEnv.LocalDirectory}\\res\\audio\\Success.wav");
                    mediaElResult.Play();

                    lblWorkOrderNo.Content = response.Data.ViaSiteRecord.WorkOrderNo;

                    if (response.Data.DutyId != Convert.ToInt32(cbDuties.SelectedValue))
                    {
                        cbDuties.SelectedValue = response.Data.DutyId;
                    }
                    else
                    {
                        response.Data.ViaSiteRecord.No = records.Count + 1;
                        records.Insert(0, response.Data.ViaSiteRecord);
                        BindGridRecords();
                    }

                    if (winIvResult != null && PresentationSource.FromVisual(winIvResult) != null)
                    {
                        winIvResult.SetIVResult(response.Data.IVData);
                    }
                }));
            }
            catch (Exception ex)
            {
                CommonMessage.Alert(this, $"过站失败，请拍照发给IT，并重新尝试过站\r\nPassing failed, please take a picture and send it to IT\r\n{ex.ToString()}", false);
            }
        }

        private void Window_Closed(object sender, EventArgs e)
        {
            if (winIvResult != null && PresentationSource.FromVisual(winIvResult) != null)
            {
                winIvResult.Close();
            }
            Environment.Exit(0);
        }

        private void Menu_Click(object sender, RoutedEventArgs e)
        {
            switch (((System.Windows.Controls.MenuItem)sender).Name)
            {
                case "btnSettings":
                    new SettingsIndex().ShowDialog();
                    break;
                case "btnMissingRecords":
                    new MissingSiteRecord(Convert.ToInt32(cbMachines.SelectedValue)).Show();
                    break;
                case "btnPassIv":
                    new WinPassIv().Show();
                    break;
                case "btnLogout":
                    new LoginWindow(false).Show();
                    this.Hide();
                    break;
                case "btnAbout":
                    System.Windows.MessageBox.Show($"AISUNMes Product Version:{FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).ProductVersion}");
                    break;
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (winIvResult != null && PresentationSource.FromVisual(winIvResult) != null)
            {
                winIvResult.Close();
            }
        }
    }
}
